#!/usr/bin/env python

import logging
import logging.config

# Set up the logger - if we don't read the config before loading the
# other modules, the logging doesn't

logging.config.fileConfig('updateCache.config')
logger = logging.getLogger('allConverging.updateCache')

import sys
import allconsuming.webdac
import allconsuming.filedac
import time
import optparse
import urllib2

MINIMUM_USER_AGE = 3 * 24 * 3600 
MINIMUM_ITEM_AGE = 24 * 3600 


def parseArgs(args):
    optParser = optparse.OptionParser()
    optParser.add_option('-v', '--verbose', action='store_true', dest='verbose', default=False,
                         help="provide feedback about what's gonig on")
    optParser.add_option('-t', '--time', action='store', type='int', dest='time',
                         default=60, help='number of seconds between updates')

    return optParser.parse_args(args)

def verbose(message):
    global options
    if options.verbose:
        print message
    logger.info(message)

def updateUser(userName):
    oldR = allconsuming.filedac.getUserConsumables(userName)
    r = allconsuming.webdac.getUserConsumables(userName)
    if (oldR is None and r is not None):
        logger.info('user ' + userName + ' is new')
    elif len(r) != len(oldR):
        verbose('user %s had consumed %d items, but now has %d' % (userName, len(oldR), len(r)))
    logger.debug('saving user ' + userName + ' to cache')
    allconsuming.filedac.saveUserConsumables(userName, r)

def updateItem(itemNumber):
    oldConsumables = allconsuming.filedac.getItemConsumables(itemNumber)

    consumables = allconsuming.webdac.getItemConsumables(itemNumber)
    oldUsers = [c.userName for c in consumables]

    newConsumables = []
    for c in consumables:
        if c.userName not in oldUsers:
            verbose('  user ' + c.userName + ' is new')
            newConsumables.append(c)
    logger.debug('saving item ' + itemNumber + ' to cache')
    allconsuming.filedac.saveItemConsumables(itemNumber, consumables)
    return newConsumables

def main(args=None):
    global options

    if args == None:
        args = sys.argv[1:]

    (options, args) = parseArgs(args)

    limit = 20
    while True:
        logger.info('fetching list of items to refresh')
        allItems = allconsuming.filedac.getItemList()
        allItems = [((x[0] + MINIMUM_ITEM_AGE, x[1]),'i') for x in allItems]

        logger.info('fetching list of users to refresh')
        allUsers = allconsuming.filedac.getUserList()
        allUsers = [((x[0] + MINIMUM_USER_AGE, x[1]),'u') for x in allUsers]

        allThings = allUsers + allItems
        allThings.sort()
        allThings = allThings[:limit]

        try:
            index = 0
            while index < len(allThings):
                sleepTime = options.time
                
                thing = allThings[index]
                #print thing
                
                index += 1
                
                nextUpdateTime = thing[0][0]
                logger.debug(thing[0][1] + "'s next update time is %d-%02d-%02d %02d:%02d:%02d" % time.localtime(nextUpdateTime)[:6])
                if nextUpdateTime > time.time():
                    logger.debug(thing[0][1] + ' is young')
                    sleepTime = sleepTime * 5

                if thing[1] == 'u':
                    # User
                    user = thing[0][1]
                    verbose('updating cache for user ' + user)
                    updateUser(user)

                else:
                    # Item
                    item = thing[0][1]
                    verbose('updating cache for item ' + item)
                    consumables = updateItem(item)
                    for c in consumables:
                        if not allconsuming.filedac.doesUserExist(c.userName):
                            verbose('  adding user ' + c.userName + ' to the fetch list')
                            # add the user just after the current item
                            allThings[index:index] = [((1, c.userName), 'u')]

                logger.debug('sleeping for ' + str(sleepTime) + ' seconds')
                time.sleep(sleepTime)

        except urllib2.URLError, e:
            verbose('caught an exception - ' + str(e))
            verbose('sleeping for 5 minutes')
            time.sleep(300)
            #verbose('done sleeping')

        except urllib2.HTTPError, e:
            verbose('caught an exception - ' + str(e))
            verbose('sleeping for 5 minutes')
            time.sleep(300)
            #verbose('done sleeping')

        except KeyboardInterrupt:
            print 'Received a KeyboardInterrupt. Bailing.'
            break

    return 0


if __name__ == '__main__':
    sys.exit(main())

